package meta.api.web.common.presentation.interceptor;

import java.util.Date;
import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerInterceptor;

import com.auth0.jwt.JWT;
import com.auth0.jwt.JWTVerifier;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.exceptions.JWTDecodeException;
import com.auth0.jwt.exceptions.JWTVerificationException;

import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import meta.api.web.account.business.UserMngService;
import meta.api.web.account.businessinfo.UserInfo;
import meta.api.web.common.auth.ApiAuthorization;
import meta.api.web.common.util.ApiConst;
import meta.api.web.common.util.ApiUtil;
import meta.common.util.ListUtil;
import meta.common.util.StrUtil;

@Component
public class ApiAuthChkInterceptor implements HandlerInterceptor {

    // private static final String ERROR_MSG_NOT_TOKEN = "无权限令牌，请重新登录。";
    // private static final String ERROR_MSG_ERROR_TOKEN = "权限令牌错误，请重新登录。";
    // private static final String ERROR_MSG_ERROR_ACCOUNT = "账号不存在，请重新登录。";
    // private static final String ERROR_MSG_EXPRIED_TOKEN = "权限令牌已过期，请重新登录。";

    @Autowired
    private UserMngService userMngService;

    @Override
    public boolean preHandle(HttpServletRequest req, HttpServletResponse res, Object hdl) throws Exception {
        if(!(hdl instanceof HandlerMethod)){
            return true;
        }

        String token = req.getHeader("Authorization");

        if (StrUtil.isEmpty(token)) {
            // ApiUtil.setErrorJsonResponse(res, ERROR_MSG_NOT_TOKEN);
            ApiUtil.setUnauthorizedResponse(req, res);
            return false;
        }

        if (token.startsWith("Bearer")) {
            token = token.substring(6);
            token = token.trim();
        }

        String account = null;
        try {
            account = JWT.decode(token).getAudience().get(0);
        } catch (JWTDecodeException e) {
            // ApiUtil.setErrorJsonResponse(res, ERROR_MSG_ERROR_TOKEN);
            ApiUtil.setUnauthorizedResponse(req, res);
            return false;
        }

        UserInfo user = userMngService.getUser(account, true);
        if (user == null) {
            // ApiUtil.setErrorJsonResponse(res, ERROR_MSG_ERROR_ACCOUNT);
            ApiUtil.setUnauthorizedResponse(req, res);
            return false;
        }

        JWTVerifier verifier = JWT.require(Algorithm.HMAC256(user.getPassword())).build();
        try {
            verifier.verify(token);
        } catch (JWTVerificationException e) {
            // ApiUtil.setErrorJsonResponse(res, ERROR_MSG_ERROR_TOKEN);
            ApiUtil.setUnauthorizedResponse(req, res);
            return false;
        }

        long nowTime = System.currentTimeMillis();
        long expTime = JWT.decode(token).getExpiresAt().getTime();
        if (nowTime > expTime) {
            // ApiUtil.setErrorJsonResponse(res, ERROR_MSG_EXPRIED_TOKEN);
            ApiUtil.setUnauthorizedResponse(req, res);
            return false;
        }

        // 获取请求URL
        String reqUrl = getReqUrl(req);

        if (StrUtil.isEmpty(reqUrl)) {
            ApiUtil.setBadRequestResponse(req, res);
            return false;
        }

        // auth.xml权限判定
        if (!authCheck(user, reqUrl)) {
            ApiUtil.setForbiddenResponse(req, res);
            return false;
        }

        req.getSession().removeAttribute(ApiConst.SESSION_LOGIN_USER);
        req.getSession().setAttribute(ApiConst.SESSION_LOGIN_USER, user);

        return true;
    }

    private String getReqUrl(HttpServletRequest req) {
        String url = req.getRequestURI();
        return StrUtil.isEmpty(url)
                ? null : url.endsWith("/")
                ? url : url + "/";
    }

    private boolean authCheck(UserInfo user, String reqUrl) throws Exception {
        List<Long> roleAuthCdList = user.getRoleAuthCdList();

        boolean isUrlMatcehed = false;
        for (String url : ApiAuthorization.getAuthMap().keySet()) {
            if (reqUrl.startsWith(url)) {
                isUrlMatcehed = true;

                if (ListUtil.isNotEmptyList(roleAuthCdList)) {
                    for (Long roleAuthCd : roleAuthCdList) {
                        // 权限检证
                        boolean haveAuth = ApiAuthorization.auth(roleAuthCd, url);

                        if (haveAuth) {
                            return true;
                        }
                    }
                }

                break;
            }
        }

        if (isUrlMatcehed) {
            return false;
        } else {
            // API权限没有配置的场合，认为不需要权限检证。
            return true;
        }
    }
}
